using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using T.FAS.Runtime.Metadata.Entity;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Expression.Entity;
using T.FAS.Runtime.Expression.Service;
using T.FAS.Runtime.Action.SPI;

namespace T.FAS.Runtime.Action.Engine
{
    public class ActionParamMappingHandler 
    {
        public static Dictionary<string, object> BuildParamsByMapping(ActionExecContext context)
        {
            var paramList = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
            var action = context.MetaData as ActionMetaData;
            if (action == null)
                return paramList;
            if (string.IsNullOrEmpty(action.ParamMappingJS))
                return paramList;
            var inParamsAndVariable = action.MethodParams.FindAll(x => x.ParamType == Metadata.Entity.ParamType.In || x.ParamType == ParamType.Variable);

            if (inParamsAndVariable != null && inParamsAndVariable.Count > 0)
            {
                var pageIndex = inParamsAndVariable.Find(x => x.Code.Equals(ActionMetaDataConst.ActionMetaDataParamForPageIndex));
                var pageCount = inParamsAndVariable.Find(x => x.Code.Equals(ActionMetaDataConst.ActionMetaDataParamForPageCount));
                var dynamicFilter = inParamsAndVariable.Find(x => x.Code.Equals(ActionMetaDataConst.ActionMetaDataParamForDynamicFilter));
                var dynamicSort = inParamsAndVariable.Find(x => x.Code.Equals(ActionMetaDataConst.ActionMetaDataParamForDynamicSort));
                if (context.FASContext == null)
                    context.FASContext = new FASContext();
                if (pageIndex != null && context.DataContent.ContainsKey(pageIndex.Code))
                {
                    var tmpPageIndex = context.DataContent[pageIndex.Code];
                    var pageIndexValue = 0;
                    if (tmpPageIndex != null)
                    {
                        if (Int32.TryParse(Convert.ToString(tmpPageIndex), out pageIndexValue))
                        {
                            context.FASContext.SetValue(ActionMetaDataConst.ActionMetaDataParamForPageIndex, Convert.ToString(tmpPageIndex));
                        }
                        else
                            throw new FasException(ActionExecuteExceptionCode.ActionExecuteEngineExecuteError, string.Format(CommonStringClassEngine.ActionParamMappingHandler_BuildParamsByMapping,Convert.ToString(tmpPageIndex)));
                    }

                }
                if (pageCount != null && context.DataContent.ContainsKey(pageCount.Code))
                {

                    var tmpPageCount = context.DataContent[pageCount.Code];
                    var pageCountValue = 0;
                    if (tmpPageCount != null)
                    {
                        if (Int32.TryParse(Convert.ToString(tmpPageCount), out pageCountValue))
                        {
                            context.FASContext.SetValue(ActionMetaDataConst.ActionMetaDataParamForPageCount, Convert.ToString(tmpPageCount));
                        }
                        else
                            throw new FasException(ActionExecuteExceptionCode.ActionExecuteEngineExecuteError, string.Format(CommonStringClassEngine.ActionParamMappingHandler_BuildParamsByMapping1,Convert.ToString(tmpPageCount)));
                    }
                }
                if (dynamicFilter != null && context.DataContent.ContainsKey(dynamicFilter.Code))
                    context.FASContext.SetValue(ActionMetaDataConst.ActionMetaDataParamForDynamicFilter, context.DataContent[dynamicFilter.Code]);
                if (dynamicSort != null && context.DataContent.ContainsKey(dynamicSort.Code))
                {
                    var sortFilterList = context.DataContent[dynamicSort.Code];
                    var sortFilter = "{}";
                    var sortArray = new JArray();
                    if (!string.IsNullOrEmpty(Convert.ToString(sortFilterList)))
                    {
                        sortFilter = Convert.ToString(sortFilterList).TrimStart('{').TrimEnd('}');
                        sortArray = JsonConvert.DeserializeObject<JArray>(sortFilter);
                    }
                    context.FASContext.SetValue(ActionMetaDataConst.ActionMetaDataParamForDynamicSort, sortArray);
                }
                var otherParams = inParamsAndVariable.FindAll(x => !x.Code.Equals(ActionMetaDataConst.ActionMetaDataParamForPageIndex) && !x.Code.Equals(ActionMetaDataConst.ActionMetaDataParamForPageCount)
                && !x.Code.Equals(ActionMetaDataConst.ActionMetaDataParamForDynamicFilter) && !x.Code.Equals(ActionMetaDataConst.ActionMetaDataParamForDynamicSort));
                {
                    if (otherParams != null && otherParams.Count > 0)
                    {
                        otherParams.ForEach(p =>
                        {
                            if (context.DataContent.ContainsKey(p.Code))
                                context.FASContext.SetValue(p.Code, context.DataContent[p.Code]);
                            else
                            {
                                if (!string.IsNullOrEmpty(p.DefaultValue))
                                {
                                    context.FASContext.SetValue(p.Code, p.DefaultValue);
                                }
                                else
                                {
                                    context.FASContext.SetValue(p.Code,"");
                                }
                            }
                        });
                    }
                }
            }
            //这里的MappingResult可能包含了对变量的处理结果，所以处理结果要对变量值进行更新，后面的脚本之类的执行才可以用
            var mappingResult = ExprService.GetInstance.Execute(action.ParamMappingJS, context.FASContext, context.DataContent);
            if (mappingResult.State == ResultState.Fail)
            {
                throw new FasException(ActionExecuteExceptionCode.ActionExecuteEngineExecuteError, string.Format(CommonStringClassEngine.ActionParamMappingHandler_BuildParamsByMapping2,mappingResult?.RowNum,mappingResult?.ErrMsg));
            }
            RefreshActionVariables(action, context.FASContext);
            RefreshActionExecuteContext(context);
            var newParamList = new Dictionary<string, object>();
            var resultObj = mappingResult.Result;
            if (resultObj != null)
            {
                newParamList = ConvertToObjectDictionary(resultObj);
                //newParamList = resultObj.ToObjectDictionary();
            }

            if (newParamList != null && newParamList.Count > 0)
            {
                if (paramList != null && paramList.Count >= 0)
                {
                    var resultParamList = new Dictionary<string, object>(paramList, StringComparer.OrdinalIgnoreCase);
                    foreach (var k in newParamList.Keys)
                    {
                        resultParamList[k] = newParamList[k];

                    }
                    return resultParamList;
                }
            }
            else
            {
                //如果通过参数映射脚本没有返回具体的集合，默认要把当前的原始入参值作为参数
                var inParams = inParamsAndVariable.FindAll(p=>p.ParamType == ParamType.In);
                if (inParams != null && inParams.Count > 0)
                {
                    inParams.ForEach(p =>
                    {
                        if (!context.DataContent.ContainsKey(p.Code) && p.DefaultValue == null &&!p.IsAllowNull)
                        {
                            throw new FasException(ActionExecuteExceptionCode.ActionExecuteParamNullError, string.Format(CommonStringClassEngine.ActionParamMappingHandler_BuildParamsByMapping3,p.Code));
                        }
                        if (context.DataContent.ContainsKey(p.Code))
                        {
                            paramList[p.Code] = context.DataContent[p.Code];
                        }
                        else
                        {
                            paramList[p.Code] = p.DefaultValue;
                        }
                    });
                }
            }

            context.MetaData = action;

            return paramList;
        }
        /// <summary>
        /// 将FasContext中的变量相关内容更新到参数变量中，用于脚本等逻辑的执行
        /// </summary>
        /// <param name="action"></param>
        /// <param name="context"></param>
        private static void RefreshActionVariables(ActionMetaData action, FASContext context)
        {
            if (action == null || action.MethodParams == null || action.MethodParams.Count <= 0)
                return;
            if (context == null)
                return;
            var inParamsAndvariables = action.MethodParams.FindAll(p=>p.ParamType == ParamType.Variable || p.ParamType == ParamType.Variable);
            if (inParamsAndvariables != null && inParamsAndvariables.Count > 0)
            {
                inParamsAndvariables.ForEach(v =>
                {
                    var tmpValue = context.GetValue(v.Code);
                    if (tmpValue != null)
                        v.ParamValue = tmpValue;
                });
            }            
        }

        private static void RefreshActionExecuteContext(ActionExecContext actionContext)
        {
            var expressionContext = actionContext.FASContext;
            if (expressionContext != null)
            {
                if (actionContext.DataContent == null)
                    actionContext.DataContent = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
                var keyList = expressionContext.GetDynamicMemberNames().ToList();
                foreach (var key in keyList)
                {
                    if (key.Equals(ActionRTPConst.FasActionReturnData, StringComparison.OrdinalIgnoreCase) ||
                        key.Equals(ActionRTPConst.FasActionCommonResult, StringComparison.OrdinalIgnoreCase))
                        continue;
                    var tmpValue = expressionContext.GetValue(key);
                    if (tmpValue != null)
                        actionContext.DataContent[key] = tmpValue;
                }
            }
        }
        public static Dictionary<string, object> ConvertToObjectDictionary(object obj)
        {
            if (obj == null)
            {
                return null;
            }

            Dictionary<string, object> dictionary = obj as Dictionary<string, object>;
            if (dictionary != null)
            {
                return dictionary;
            }

            IDictionary<string, object> dictionary2 = obj as IDictionary<string, object>;
            if (dictionary2 != null)
            {
                return new Dictionary<string, object>(dictionary2);
            }
            return new Dictionary<string, object>();
            
        }
    }
}
